package com.world.rickcloudendpoint.queue;

import com.world.rickcloudendpoint.common.exception.QueueEmptyException;
import com.world.rickcloudendpoint.common.exception.QueueFullException;

import java.util.Arrays;

/**
 * @description: 环形队列
 * @author: jlsong
 * @date: 2022/06/02 06:00:49
 * @version: 1.0
 */
public class CircularQueue<E> {
    // Current circular queue size
    private volatile int currentSize;
    // 环形队列元素
    private E[] elements;
    // 环形队列最大数量
    private int capacity;

    // 环形队列尾巴位置(new element enqueued at rear)
    private volatile int rear;
    // 环形队列开头位置(element will be dequeued from front)
    private volatile int front;

    public CircularQueue(int capacity) {
        if (capacity < 1) {
            capacity = Integer.MAX_VALUE;
        }
        this.capacity = capacity;
        elements = (E[]) new Object[this.capacity];
        currentSize = 0;
        front = -1;
        rear = -1;
    }

    /**
     * 从后方插入元素进队列
     *
     * @param item 元素
     * @throws QueueFullException
     */
    public void enqueue(E item) throws QueueFullException {
        if (isFull()) {
            throw new QueueFullException("队列已满，元素不能被添加.");
        }
        rear = (rear + 1) % elements.length;
        elements[rear] = item;
        currentSize++;
        if (front == -1) {
            front = rear;
        }
    }

    /**
     * 从队列头移除元素
     *
     * @return
     * @throws QueueEmptyException
     */
    public E dequeue() throws QueueEmptyException {
        if (isEmpty()) {
            throw new QueueEmptyException("队列已空，元素不能被恢复");
        }
        E element = elements[front];
        elements[front] = null;
        front = (front + 1) % elements.length;
        currentSize--;
        return element;
    }

    /**
     * 检查队列是否已满
     *
     * @return true:full;false::not full
     */
    public boolean isFull() {
        return (currentSize == elements.length);
    }

    /**
     * 检查队列是否已空
     *
     * @return true:empty;false:not empty
     */
    public boolean isEmpty() {
        return (currentSize == 0);
    }


    @Override
    public String toString() {
        return "CircularQueue [" + Arrays.toString(elements) + "]";
    }


    public static void main(String[] args) throws Exception {

        CircularQueue<Integer> circularQueue = new CircularQueue(8);

        circularQueue.enqueue(15);
        circularQueue.enqueue(16);
        circularQueue.enqueue(17);
        circularQueue.enqueue(18);
        circularQueue.enqueue(19);
        circularQueue.enqueue(20);
        circularQueue.enqueue(21);
        circularQueue.enqueue(22);

        System.out.println("Full Circular Queue" + circularQueue);

        System.out.print("Dequeued following element from circular Queue ");
        System.out.println(circularQueue.dequeue() + " ");
        circularQueue.enqueue(23);
        System.out.println("After enqueueing circular queue with element having value 23");
        System.out.println(circularQueue);
    }
}
